package command

import (
	"errors"
	"strings"
	"time"

	"gitee.com/sansaniot/ssiot-core/logger"
	"gorm.io/gorm"

	"ssdevice/common/constant"
	"ssdevice/common/dto"
	"ssdevice/common/enums"
	"ssdevice/common/utils"
	"ssdevice/internal/device/models"
	"ssdevice/internal/device/models/query"
)

type DeviceInsertReq struct {
	Sn            string                 `json:"sn" comment:"设备SN" vd:"len($)>0"`
	Name          string                 `json:"name" comment:"设备名"`
	DeptId        string                 `json:"deptId" comment:"分组id"`
	Type          string                 `json:"type" comment:"设备类型"`
	ProductModel  string                 `json:"productModel" comment:"产品编码"`
	GatewaySn     string                 `json:"gatewaySn" comment:"接入网关"`
	Location      map[string]interface{} `json:"location" comment:"地址经纬度"`
	View          map[string]interface{} `json:"view" comment:"个性页"`
	ProfileCustom map[string]interface{} `json:"profileCustom" comment:"自定义profile"`
	dto.UserInfo  `search:"-"`

	SoftCmd       string `json:"softCmd" comment:"软网关服务的启动命令"`
	FromLoginInit bool   `comment:"添加来自设备接入"`
}

func (d *DeviceInsertReq) Generate(db *gorm.DB, model *models.SysDev) (models.SysDevSchema, models.SysDevConfig, error) {
	productSchema := models.SysDevSchema{}
	productConfig := models.SysDevConfig{}
	model.Id = utils.SimpleUUID()
	model.Sn = strings.TrimSpace(d.Sn)
	model.Name = strings.TrimSpace(d.Name)
	if len(model.Name) == 0 {
		model.Name = model.Sn
	}
	devDeptFlag := len(d.DeptId) > 0
	fromLoginDefault := d.FromLoginInit && d.ProductModel == constant.DefaultProductCode
	model.DeptId = utils.If(devDeptFlag, d.DeptId, constant.AnonymousGroupId).(string)
	if fromLoginDefault {
		model.DeptId = constant.AnonymousGroupId
	}
	model.Type = d.Type
	model.ProductModel = d.ProductModel
	if d.Sn != d.GatewaySn {
		model.GatewaySn = d.GatewaySn
	}
	var location map[string]interface{}
	if d.Location != nil {
		location = d.Location
	} else {
		location = map[string]interface{}{
			"address": "",
			"lng":     nil,
			"lat":     nil,
		}
	}
	model.Location = utils.MapToBytes(location)
	model.View = utils.MapToBytes(utils.If(len(d.View) > 0, d.View, map[string]interface{}{}).(map[string]interface{}))
	model.OnlineStatus = enums.Offline
	now := dto.LocalTime(time.Now())
	model.CreateTime = &now
	model.UpdateTime = &now

	// 根据产品生成
	if err := genFromProduct(db, model, &productSchema, &productConfig, devDeptFlag || fromLoginDefault); err != nil {
		return productSchema, productConfig, err
	}

	//if model.Type == enums.DevTypeOfDevice && len(model.GatewaySn) == 0 {
	//	return productSchema, errors.New("未指定网关SN")
	//}
	//if model.Type == enums.DevTypeOfSoftGateway && len(d.SoftCmd) == 0 {
	//	return errors.New("未指定软网关服务命令")
	//}
	return productSchema, productConfig, nil
}

func genFromProduct(db *gorm.DB, devModel *models.SysDev, productSchema *models.SysDevSchema, productConfig *models.SysDevConfig, devHasDept bool) error {
	if len(devModel.ProductModel) == 0 {
		return nil
	}
	pd := &models.SysDevProduct{}
	pd.Orm = db
	if err := pd.FindOne(pd, dto.MakeCondition(query.SysProductQuery{ProductModel: devModel.ProductModel})); err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			err = errors.New("添加设备,产品编码无法识别")
		}
		return err
	}
	//if devModel.Type != pd.DeviceType {
	//	return errors.New("设备类型与所选产品不一致")
	//}
	// 不再校验不一致  直接取产品的类型
	if len(pd.DeviceType) > 0 {
		devModel.Type = pd.DeviceType
	} else {
		return errors.New("产品类型信息异常")
	}
	productSchema.Orm = db
	if err := productSchema.FindOne(productSchema, dto.MakeCondition(query.SysDevSchemaQuery{ProductId: pd.Id})); err != nil {
		logger.Error(err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			logger.Error("添加设备,产品schema缺失")
			return nil
		}
		return err
	}
	productConfig.Orm = db
	if err := productConfig.FindOne(productConfig, dto.MakeCondition(query.SysDevConfigQuery{ProductId: pd.Id})); err != nil {
		logger.Error(err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			logger.Error("添加设备,产品config缺失")
			return nil
		}
		return err
	}
	if !devHasDept {
		// 设备没指定deptId才使用产品的
		devModel.DeptId = pd.DeptId
	}
	now := dto.LocalTime(time.Now())
	// 复制成设备schema
	(*productSchema).Id = utils.SimpleUUID()
	(*productSchema).DevSn = devModel.Sn
	(*productSchema).CreateTime = &now
	(*productSchema).UpdateTime = &now
	(*productSchema).ProductModel = ""
	(*productSchema).DevProductId = ""
	// 复制成设备config
	(*productConfig).Id = utils.SimpleUUID()
	(*productConfig).DevSn = devModel.Sn
	(*productConfig).CreateTime = &now
	(*productConfig).UpdateTime = &now
	(*productConfig).ProductModel = ""
	(*productConfig).DevProductId = ""
	return nil
}

type DeviceEditReq struct {
	Id           string `json:"id" vd:"len($)>0"`
	Name         string `json:"name" comment:"设备名"`
	DeptId       string `json:"deptId" comment:"分组id"`
	ProductModel string `json:"productModel" comment:"产品编码"`
	//GatewaySn    string                 `json:"gatewaySn" comment:"接入网关"`
	Location     map[string]interface{} `json:"location" comment:"地址经纬度"`
	View         map[string]interface{} `json:"view" comment:"个性页"`
	dto.UserInfo `search:"-"`

	Type string `search:"-"`
}

func (d *DeviceEditReq) GenerateMap() map[string]interface{} {
	// 可编辑项
	editMap := map[string]interface{}{}
	if len(d.Name) > 0 {
		editMap["name"] = strings.TrimSpace(d.Name)
	}
	if len(d.DeptId) > 0 {
		editMap["dept_id"] = d.DeptId
	}
	//if len(d.ProductModel) > 0 {
	//	editMap["product_model"] = d.ProductModel
	//}
	if len(d.Location) > 0 {
		editMap["location"] = utils.MapToBytes(d.Location)
	}
	return editMap
}

type DeviceDeleteReq struct {
	IdSn         string `json:"idSn" vd:"len($)>0"`
	dto.UserInfo `search:"-"`

	DelType string
}

type BatchGroupReq struct {
	IdSn   string `json:"idSn" vd:"len($)>0"`
	DeptId string `json:"deptId" vd:"len($)>0"`
}

type DeviceConfigReq struct {
	IdSn         string                 `json:"idSn" vd:"len($)>0"`
	Data         map[string]interface{} `json:"data" comment:"json内容"`
	dto.UserInfo `search:"-"`

	NodePath string `json:"nodePath"`
}

type DeviceConfigDelReq struct {
	IdSn string `json:"idSn" vd:"len($)>0"`
	Key  string `json:"key" vd:"len($)>0"`

	dto.UserInfo `search:"-"`
}

type DeviceSensorReq struct {
	IdSn         string                 `json:"idSn" vd:"len($)>0"`
	Data         map[string]interface{} `json:"data" comment:"json内容" vd:"len($)>0"`
	dto.UserInfo `search:"-"`

	SenOrSys string
}

func (e *DeviceSensorReq) GetSenOrSys() string {
	return e.SenOrSys
}

type DeviceSensorDelReq struct {
	IdSn         string `json:"idSn" vd:"len($)>0"`
	Key          string `json:"key" comment:"变量key,多个逗号间隔" vd:"len($)>0"`
	dto.UserInfo `search:"-"`

	SenOrSys string
}

func (e *DeviceSensorDelReq) GetSenOrSys() string {
	return e.SenOrSys
}

type DevicePropsSetReq struct {
	IdSn         string `json:"idSn" vd:"len($)>0"`
	Async        bool   `json:"async"`
	dto.UserInfo `search:"-"`
}

type DevicePropsGetReq struct {
	IdSn         string `json:"idSn" vd:"len($)>0"`
	Path         string `json:"path"`
	Async        bool   `json:"async"`
	dto.UserInfo `search:"-"`
}

type DeviceSensorSetReq struct {
	IdSn         string                 `json:"idSn" vd:"len($)>0"`
	Data         map[string]interface{} `json:"data" vd:"len($)>0"`
	Local        *bool                  `json:"local"`
	Entire       *bool                  `json:"entire"`
	Async        bool                   `json:"async"`
	dto.UserInfo `search:"-"`
}

type DeviceSensorGetReq struct {
	IdSn         string `json:"idSn" vd:"len($)>0"`
	Path         string `json:"path"`
	Async        bool   `json:"async"`
	dto.UserInfo `search:"-"`
}

type DeviceFuncSetReq struct {
	IdSn         string                 `json:"idSn" vd:"len($)>0"`
	FuncName     string                 `json:"funcName" vd:"len($)>0"`
	Data         map[string]interface{} `json:"data" vd:"len($)>0"`
	Latency      *int                   `json:"latency"`
	Async        bool                   `json:"async"`
	dto.UserInfo `search:"-"`
}

type DeviceSaveProductReq struct {
	IdSn         string `json:"idSn" vd:"len($)>0"`
	ProductModel string `json:"productModel" vd:"len($)>0"`
	Name         string `json:"productName"`
	dto.UserInfo `search:"-"`
}

func (d *DeviceSaveProductReq) GenerateProduct(fromDev *models.SysDev, productInsert *ProductInsertReq) error {
	productInsert.Name = fromDev.Name + "产品"
	if len(d.Name) > 0 {
		productInsert.Name = d.Name
	}
	productInsert.DeviceType = fromDev.Type
	productInsert.ProductModel = d.ProductModel
	if len(productInsert.ProductModel) == 0 {
		return errors.New("保存为产品缺少产品编码")
	}
	productInsert.DeptId = fromDev.DeptId
	return nil
}
